home *** CD-ROM | disk | FTP | other *** search
- /*------------------------------------------------------------------------------
- *
- * Apple Developer Technical Support
- *
- * Edition subscribing routines
- *
- * Program: EditionSample
- * File: Subscribe.c - C Source
- *
- * by: C.K. Haun <TR>
- *
- * Copyright © 1990,1991 Apple Computer, Inc.
- * All rights reserved.
- *
- *------------------------------------------------------------------------------
- * This file handles the Subscribe section of the program. It also handles some of
- * the common use routines, like the section options dialog.
- *----------------------------------------------------------------------------*/
-
- #define __SUBSCRIBE__
-
- #pragma segment Subscribe
- #pragma load "EdSampheaders" /* see the Buildheaders.c file */
-
- #include "EdSampdefines.h"
- /* prototypes */
- OSErr MyReadSection(SectionHandle theSection);
-
- void MyCancelSection(SectionHandle inSection, WindowPtr theWindow);
- OSErr MyReadEditionData(Ptr readinPtr, DescType typeToGet, EditionRefNum readRef, Size *howMuch);
- void HandleSectionSave(windowCHandle theWind, Boolean writeEm, Boolean dereg, FSSpec *theSpec);
- void StoreSubscriber(windowCHandle shortName, SectionHandle secHandle, Handle inRect, Handle pictIn);
- pascal short SubExpOptHook(short itemOffset, short itemHit, DialogPtr theDialog, Ptr yourDataPtr);
- pascal Boolean SubExpOptFilter(DialogPtr theDialog, EventRecord *theEvent, short itemOffset, short *itemHit, Ptr yourDataPtr);
- void PasteSubscription(void);
- void CutSubscription(void);
- void CopySubscription(void);
- void KillClipSub(void);
-
- OSErr ReadClipSection(Size readIn, EditionRefNum sRefNum);
- void SkipOverSubscriber(windowCHandle inWindow, unsigned short theKey);
- extern pascal short ExpOptHook(short itemOffset, short itemHit, DialogPtr theDialog, Ptr yourDataPtr);
- extern pascal Boolean ExpOptFilter(DialogPtr theDialog, EventRecord *theEvent, short itemOffset, short *itemHit, Ptr yourDataPtr);
-
- /* external references */
- extern WindowPtr gActionWindows;
- extern WindowPtr gCurrentWindow;
- extern WindowPtr gClipWindowPtr;
- extern short gWindowCount;
- extern OSErr MyUpdateEdition(SectionHandle theSection);
- extern OSErr GetSectionHandleFromEvent(AppleEvent *AEin, SectionHandle *theSection);
- extern unsigned long gSectionID;
- extern void ShowMe(Str255 in, OSErr aevtErr);
- extern void MyCancelPublication(SectionHandle inSection);
- extern WindowPtr FindSection(SectionHandle inSection);
- extern void CheckTextSections(windowCHandle inWindow, short Action);
- extern Boolean gShowPub;
- extern Boolean gShowSub;
- extern Boolean gExpanded;
- extern Boolean gResizeSub;
- extern short gClipHasContents;
- extern SectionHandle gClipSection;
- extern PicHandle gClipPict;
- extern Handle gScrapData;
- extern EditionOpenerProcPtr gOriginalOpener;
- extern void ReadDocData(windowCHandle newWindControl, short readRefNum);
- extern WindowPtr AddNewWindow(Boolean showIt);
- extern OSErr MySetHandleSize(Handle theHandle, Size theSize);
- extern void RePackText(textSectionHandle currentSection, TEHandle theTEHandle);
- extern textSectionHandle GetTextSection(windowCHandle shortName, SectionType what);
- extern textSectionHandle TextSectionFromSecHandle(SectionHandle theSection);
-
- /* this point tells EM to center our expanded box, if we're using that feature */
- Point expPoint =
- {
- -1, -1
- };
-
-
-
-
- /* DoSubscribe presents the user with the Subscriber dialog, and allows the user to */
- /* subscribe to a PICT type edition, anywhere, anytime. It also stores the */
- /* section handle returned in the window data structure for the current window */
- /* You can only subscribe to TEXT if you have a text box open in the current window. */
- /* Optionally, of course, you can put in your own conversion of the TEXT to a PICT and */
- /* subscribe to that as such, same as you would with clipboard types. */
-
- void DoSubscribe(void)
- {
- OSErr myErr;
- SectionHandle secHandle;
- windowCHandle shortName;
- NewSubscriberReply GetSub;
- shortName = (windowCHandle)GetWRefCon(gCurrentWindow); /* get our struct */
- GetSub.formatsMask = kPICTformatMask; /* tell the dialog we only want PICT type editions */
- if ((*shortName)->boxHandle != nil) /* is there a text box already? */
- GetSub.formatsMask += kTEXTformatMask;
- /* GetLastEditionContainerUsed gives you either the last edition container used */
- /* (either pub or sub, since they are the same to the Edition Manager) or if there */
- /* was not a previous container, it fills it with a default container. */
- GetLastEditionContainerUsed(&GetSub.container);
- /* Now ask the user to select an edition to subscribe to */
- if (!gExpanded)
- myErr = NewSubscriberDialog(&GetSub);
- else
- myErr = NewSubscriberExpDialog(&GetSub, expPoint, kExpandedDITL, (ExpDlgHookProcPtr)ExpOptHook,
- (ExpModalFilterProcPtr)ExpOptFilter, nil);
- if (myErr != noErr) { /* bail on fail */
- ShowMe("\pNewSubscriberDialog", myErr);
- return;
- }
- if (GetSub.canceled) /* did they cancel the dialog? */
- return;
- HLock((Handle)shortName);
- /* Now create a new section record for the container the user picked. In other words, the */
- /* Edition manager keeps track of things by the container, and will give you a section */
- /* record that refers to it for you to keep track with. */
- /* ••• NOTE: Whenever the Edition Manager gives you memory (like the section handle) */
- /* it came out of your heap, and YOU are responsible for disposing of it when you are */
- /* completely done (and have UnRegistered) the section. If you're not careful about this */
- /* then you'll get creeping memory loss. */
- /* Now see if the window has ever been saved. If so, we can store a reference to */
- /* the file in the section */
- if (GetHandleSize((Handle)(*shortName)->fileAliasHandle) == 0) {
- myErr = NewSection(&GetSub.container, nil, stSubscriber, (*shortName)->windowID + gSectionID, sumAutomatic, &secHandle);
- } else {
- /* if the file has been saved once, then we can store a reference to the 'parent' file */
- /* in the edition */
- FSSpec tempSpec;
- Boolean myWasChanged;
- myErr = ResolveAlias(nil, ((*shortName)->fileAliasHandle), &tempSpec, &myWasChanged);
- myErr = NewSection(&GetSub.container, &tempSpec, stSubscriber, (*shortName)->windowID + gSectionID, sumAutomatic,
- &secHandle);
- }
- if (myErr != noErr) {
- ShowMe("\pNewSection", myErr);
- return;
- }
- /* section successfully gotten. Add it to the current window section list please */
- /* Handle this in whatever way is appropriate for your application, of course. */
- /* The main point to remember is that you _must_ keep track of the section handles, */
- /* they are your method (only method) for comunication between your application */
- /* and the Edition Manager, you will be passing sections to the EM, and it will be */
- /* passing them back to you. */
- gSectionID++; /* increment our unique ID */
- StoreSubscriber(shortName, secHandle, nil, nil);
- HUnlock((Handle)shortName);
- }
-
- /* end DoSubscribe */
- /* DoOptions handles the SectionOptions menu selection. The handle passed */
- /* (inSection) is a subscriber OR publisher section, the Edition Manager will figure */
- /* out what dialog to display by looking at the section record */
- /* ••• BE CAREFUL with the section handle you pass to the options dialog (or anywhere, for that matter) */
- /* A section that has not been registered, or a section containing a bad alias handle, will */
- /* cause the options dialog to blow up in unusual and fun ways */
- /* This call also includes the expanded section options dialog box with one */
- /* extra item, to show how it's used. */
- void DoOptions(SectionHandle inSection)
- {
- OSErr myErr;
- SectionOptionsReply oreply;
- Boolean subExpansion;
-
- oreply.sectionH = inSection; /* put the section passed in the reply record */
- if ((*inSection)->kind == stSubscriber)
- subExpansion = true;
- else
- subExpansion = false;
- myErr = IsRegisteredSection(inSection);
- if (myErr != noErr) {
- ShowMe("\p Bad Section ", myErr);
- return;
- }
- if (subExpansion) {
- myErr = SectionOptionsExpDialog(&oreply, expPoint, kExpandedSubDITL, (ExpDlgHookProcPtr)SubExpOptHook,
- (ExpModalFilterProcPtr)SubExpOptFilter, nil);
- } else {
- if (!gExpanded)
- myErr = SectionOptionsDialog(&oreply); /* run the dialog */
- else
- myErr = SectionOptionsExpDialog(&oreply, expPoint, kExpandedDITL, (ExpDlgHookProcPtr)ExpOptHook,
- (ExpModalFilterProcPtr)ExpOptFilter, nil);
- }
- if (myErr != noErr) {
- ShowMe("\pSection Options", myErr);
- return;
- }
- if (oreply.canceled) /* if user canceled */
- return;
- if (oreply.action == sectionReadMsgID) {
- /* if the user clicked 'Get Edition Now' you'll call your section read routine, the same */
- /* one that gets called on a sect read AppleEvent */
- MyReadSection(inSection);
- } else {
- if (oreply.action == sectionWriteMsgID) {
- /* if the user clicked 'Send Edition Now' you'll call your section write routine, the same */
- /* one that gets called on a sect writ AppleEvent */
- MyUpdateEdition(inSection);
- } else {
- if (oreply.action == 'goto') {
- /* this is the sect scrl (section scroll) event from the dialog */
- /* the dialog has already taken the action for you, that's it's job */
- } else {
- if (oreply.action == emCancelSectionDialogRefCon) {
- /* This is for canceling a section, either pub or sub, you have to make the */
- /* choice based on what the section is */
- SectionType tempST;
- HLock((Handle)inSection);
- tempST = (*inSection)->kind; /* what kinda thing is this? */
- HUnlock((Handle)inSection);
-
- MyCancelSection(inSection, FindSection(inSection));
- }
- }
- }
- }
- }
-
- /* end DoOptions */
-
- /* AEReadSectionHandler is the handler I installed in the AppleEvent manager list for */
- /* AppleEvents of the type 'sect' 'read'. What this means is that whenever I get a */
- /* high level event of the type 'sect' 'read' this routine will be dispatched to when I */
- /* call AEProcessAppleEvent (in AppleEventM.c). This is where the actual section data */
- /* gets read in, when the Edition Manager tells you the edition is ready to read */
- pascal OSErr AEReadSectionHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
- {
- #pragma unused (reply,refIn)
- SectionHandle theSection;
- OSErr myErr;
-
- myErr = GetSectionHandleFromEvent(messagein, &theSection); /* in AppleEventM.c */
- if (myErr) {
- ShowMe("\pGetSectionHandleFromEvent", myErr);
- return(myErr);
- }
- /* This next step is very important. Unexpected things can happen to you, */
- /* a section could disappear between the time an event gets posted and when it */
- /* finally gets to your application (particularly since AppleEvents are the lowest in */
- /* the event hierarchy), the section may have been canceled, deleted, disk off-line, or */
- /* whatever. You must make a current check with the EM to see if the section that */
- /* you are supposed to read. */
- myErr = IsRegisteredSection((SectionHandle)theSection);
- if (myErr) {
- ShowMe("\pRead IsRegisteredSection", myErr);
- return(myErr);
- }
- /* It is a valid section. Jump to my routine that opens and reads it */
- MyReadSection(theSection);
- }
-
- /* end AEReadSectionHandler */
-
- /* MyReadSection opens and reads the edition data into my window data structure. */
- OSErr MyReadSection(SectionHandle theSection)
- {
- OSErr readErr;
- OSErr myErr;
- EditionRefNum sRefNum;
- Size dataSize;
- Boolean existed = false; /* for setting the display rect */
- /* open the edition and get a ref number */
- SetCursor(*GetCursor(watchCursor));
- myErr = OpenEdition(theSection, &sRefNum);
- if (myErr) {
- ShowMe("\pOpenEdition", myErr);
- return(myErr);
- }
- /* Here we are double-checking the edition. I'm first checking for PICT data, */
- /* and as a handy side effect, it gives us the size of the data (returned in my */
- /* variable dataSize) for us to use when we read it later */
- if (noErr == (myErr = EditionHasFormat(sRefNum, 'PICT', &dataSize))) {
- /* It does have a pict, read it in */
- register qq, jj; /* loop vars for window search */
- long subIDtofind;
-
- /* There is already a handle allocated for this picture in the window structure.
- * Find it, resize it (since the edition size could have changed) and fill it.
- * Keep in mind that the section read may happen for a window which is not
- * frontmost, so we need to search all the windows to find the ID */
- WindowPtr tempPort;
- Boolean secFound = false;
- SectionHandle *tempPtr;
- SectionRecord *tempRecord;
- Handle tempHandle;
- WindowPtr tempNextWindow;
- Rect *tempRect;
- Rect holdRect;
- Boolean isClip;
- HLock((Handle)theSection);
- subIDtofind = (*theSection)->sectionID; /* what ID are we reading? */
- /* check to see if this is the clipboard's section. If so, let the clipboard */
- /* handle it */
- if ((subIDtofind == (*gClipSection)->sectionID) && (gClipSection != nil))
- return(ReadClipSection(dataSize, sRefNum));
- GetPort(&tempPort); /* save the current port */
- /* search window list now */
- tempNextWindow = gActionWindows; /* start at the beginning of the chain */
- for (qq = 0; qq < gWindowCount; qq++) {
- windowCHandle tempWC;
- /* do housekeeping to get to the section handle list */
- tempWC = (windowCHandle)GetWRefCon(tempNextWindow);
- HLock((Handle)tempWC);
- tempHandle = (*tempWC)->subs; /* handle containing SectionHandles */
- HLock(tempHandle);
- tempPtr = (SectionHandle *)*tempHandle;
- /* Loop through all our sections until we find this edition */
- for (jj = 0; jj < (*tempWC)->numSubs; jj++) {
- Handle *newTemp;
- HLock((Handle)*tempPtr);
- tempRecord = *(*tempPtr);
- if (tempRecord->sectionID == subIDtofind) {
- /* found the section belonging to this read. */
- /* can't break, since it is conceiveable that the user has more that one subscription in this document */
- SetPort(tempNextWindow); /* set the port to the window we found the section in */
- HLock((*tempWC)->subDataHandle);
- newTemp = (Handle *)*((*tempWC)->subDataHandle);
- newTemp += jj;
- /* if the dataSize returned was -1 then the size was unknown when opened. */
- /* in this case, this should only happen with our special opener. */
- /* So, if it is -1, then we'll have to handle the read */
- /* in a series of steps to get the right amount of data */
- /* For now, I'll leave that out until I put in a custom */
- /* opener. Watch this space */
- if (dataSize != -1) {
- HUnlock(*newTemp);
- MySetHandleSize(*newTemp, dataSize);
- HLock(*newTemp);
- }
- /* read the pict in */
- myErr = MyReadEditionData(**newTemp, 'PICT', sRefNum, &dataSize);
- /* ••••• NOTE: After much discussion with our Human Interface folks and the */
- /* Edition Manager engineer, we've decided that the interface guidelines */
- /* for editions will say that reading a subscription does _not_ dirty */
- /* a document. A lot of soul-searching went on to make this decision, and */
- /* we decided this way primarily to keep the user from getting confused. */
- /* Editions should be as transparent and automatic as possible, and reminding */
- /* the user that an edition is a 'special' thing that they have to do */
- /* unusual things with to make work right will remove some of that */
- /* automation. Of course, the 'cached' version of the subscription that */
- /* you save with the document should be updated when the subscription changes */
- /* So, the following line was commented out. */
- /* (*tempWC)->windowDirty = true; */
- /* mark window dirty on every read */
- holdRect = (*(PicHandle)(*newTemp))->picFrame;
- HUnlock(*newTemp);
- /* put the picture in the corner, if it didn't exist. If it did, adjust the rect as
- * required */
- HLock((*tempWC)->subRects);
- newTemp = (Handle *)*((*tempWC)->subRects);
- newTemp += jj;
- /* if the handle is the size of a rect, I've seen this edition before */
- if (GetHandleSize(*newTemp) == sizeof(Rect)) {
- existed = true; /* it's already been made */
- } else {
- HUnlock(*newTemp);
- MySetHandleSize(*newTemp, sizeof(Rect)); /* new subscription */
- }
- HLock(*newTemp);
- tempRect = (Rect *)*(*newTemp);
- if (!existed) {
- tempRect->top = tempRect->left = 0;
- tempRect->bottom = holdRect.bottom - holdRect.top;
- tempRect->right = holdRect.right - holdRect.left;
- } else {
- InvalRect(tempRect); /* refresh the old image if the thing was resized */
- /* tempRect->bottom = tempRect->top + (holdRect.bottom - holdRect.top);
- tempRect->right = tempRect->left + (holdRect.right - holdRect.left);
- */
- }
- InvalRect(tempRect);
- HUnlock(*newTemp);
- HUnlock((Handle)*tempPtr);
-
- } else {
- HUnlock((Handle)*tempPtr);
- tempPtr += 1;
- }
- } /* section handle loop jj */
- tempNextWindow = (*tempWC)->nextWindow;
- HUnlock(tempHandle);
- HUnlock((Handle)tempWC);
- if (tempNextWindow == nil)
- break;
-
- /* ••• NOTE: You'll notice that there is no break or exit from this section searching loop */
- /* Why? Because there may be many subscribers to the same edition. The user may */
- /* have multiple subscribtions in the same window, or in any of his or her windows. */
- /* Don't assume that there is only one subscriber (unless you require it, which may be */
- /* reasonable for a single document but _not_ for a multi-document application), run */
- /* your whole list each time to be certain everything gets refreshed */
- } /* window loop qq */
- SetPort(tempPort); /* reset the port to what it was when we entered */
- } else {
- if (noErr == (myErr = EditionHasFormat(sRefNum, 'TEXT', &dataSize))) {
- WindowPtr theWindow;
- windowCHandle tempWC;
- TEHandle tempTEH;
- textSectionHandle theTES;
- long tempStart, tempEnd;
- /* it's a text subscription. That means we search in the text path, and also need */
- /* to update the TEHandle for the window this goes with */
- theWindow = FindSection(theSection);
- theTES = TextSectionFromSecHandle(theSection);
- HLock((Handle)theTES);
- tempWC = (windowCHandle)GetWRefCon(theWindow);
- tempTEH = (*tempWC)->boxHandle;
- /* save the current TE selection range so that the user is returned to the */
- /* place he or she was before we did the reading, so the text doesn't jump */
- /* around all loony on them */
- tempStart = (*tempTEH)->selStart;
- tempEnd = (*tempTEH)->selEnd;
-
- /* first thing we need to do is remove whatever the current sub data in our */
- /* TE Record is. if there is any, o'course */
- if ((*theTES)->startChar != (*theTES)->endChar) {
- TESetSelect((*theTES)->startChar, (*theTES)->endChar, (TEHandle)tempTEH);
- TEDelete(tempTEH);
- }
- SetHandleSize((*theTES)->theText, dataSize);
- HLock((*theTES)->theText);
- MyReadEditionData(*(*theTES)->theText, 'TEXT', sRefNum, &dataSize);
- /* that gives us the text. Now we need to adjust our endpoint */
- (*theTES)->endChar = ((*theTES)->startChar) + dataSize;
- /* set insertion point to where we want to be */
- TESetSelect((*theTES)->startChar, (*theTES)->startChar, tempTEH);
- TEInsert(*(*theTES)->theText, dataSize, tempTEH);
- HUnlock((*theTES)->theText);
- HUnlock((Handle)theTES);
- /* reset insertion point to what it once was */
- TESetSelect(tempStart, tempEnd, tempTEH);
- }
- }
- }
-
- /* end MyReadSection */
-
- OSErr MyReadEditionData(Ptr readinPtr, DescType typeToGet, EditionRefNum readRef, Size *howMuch)
- {
- OSErr myErr;
- if (myErr = ReadEdition(readRef, typeToGet, readinPtr, howMuch))
- CloseEdition(readRef, false);
- else
- CloseEdition(readRef, true);
- return(myErr);
- }
-
- /* HandleSectionSave handles saving and closing of subscribers for
- * a document. The Boolean flags tell this function wheither to write
- * ouut the data (on save or save/close) and weither to UnRegister
- * the sections (on close).
- * The resource fork is open on entry.
- */
- /* theWind is locked on entry */
- void HandleSectionSave(windowCHandle theWind, Boolean writeEm, Boolean dereg, FSSpec *theSpec)
- {
- SectionHandle *theSections;
- Handle *newTemp;
- SectionRecord secRec;
- Handle tempHandle;
- Rect *tempRectPtr;
- register qq;
- OSErr myErr;
- if ((*theWind)->numSubs) {
- Handle *tempPictPtr;
- HLock((*theWind)->subs);
- theSections = (SectionHandle *)*(*theWind)->subs;
- /* and display rectangles */
- HLock((*theWind)->subRects);
- HLock((*theWind)->subDataHandle);
- newTemp = (Handle *)*((*theWind)->subRects);
- tempPictPtr = (Handle *)*((*theWind)->subDataHandle);
- /* loop through the sections */
- for (qq = 0; qq < (*theWind)->numSubs; qq++) {
- /* first update (or create, if needed, the Ed Manger will know) the alias */
- AssociateSection(*theSections, theSpec);
- /* write the section handle out... */
- if (writeEm) {
- tempHandle = (Handle)*theSections;
- HandToHand(&tempHandle);
- HLock((Handle)*theSections); /* lock down the original section so we can work with it */
- secRec = *(*(*theSections)); /* just for easier display below */
- AddResource(tempHandle, rSectionType, secRec.sectionID, "");
- /* now do the same with the alias record please */
- tempHandle = (Handle)secRec.alias;
- HandToHand(&tempHandle);
- AddResource(tempHandle, rAliasType, secRec.sectionID, "");
- HUnlock((Handle)*theSections);
- /* save off the display rect for this sub */
- tempHandle = *newTemp;
- HandToHand(&tempHandle);
- AddResource(tempHandle, 'RECT', secRec.sectionID, "");
- /* and save out the picture data, so we don't need to immediatly do a */
- /* section read when the file is opened */
- tempHandle = *tempPictPtr;
- HandToHand(&tempHandle);
- AddResource(tempHandle, 'PICT', secRec.sectionID, "");
- } /* writeEm if */
-
- if (dereg) {
- UnRegisterSection(*theSections);
- /* and dispose of the alias handle */
- DisposHandle((Handle)*(*(*theSections))->alias);
- /* and the section handle */
- DisposHandle((Handle)*theSections);
- /* and the rectangle handle */
- DisposHandle((Handle)*newTemp);
- /* picture handle disposed in closewindow */
- }
- theSections += 1; /* go to next section handle please */
- newTemp += 1; /* and next rectangle */
- }
- HUnlock((*theWind)->subRects);
- HUnlock((*theWind)->subs);
- } /* end subscriber save section */
- /* now do the same thing for our publishers please */
- /* Of course, here you'll also write the data if pumAutomatic is set */
-
- if ((*theWind)->numPubs) {
- HLock((*theWind)->pubs);
- theSections = (SectionHandle *)*(*theWind)->pubs;
- /* and display rectangles */
- HLock((*theWind)->pubRects);
- tempRectPtr = (Rect *)*((*theWind)->pubRects);
-
- /* loop through the sections */
- for (qq = 0; qq < (*theWind)->numPubs; qq++) {
- /* first update (or create, if needed, the Ed Manger will know) the alias */
- AssociateSection(*theSections, theSpec);
- /* write the section handle out... */
- if (writeEm) {
- tempHandle = (Handle)*theSections;
- HandToHand(&tempHandle);
- HLock((Handle)*theSections); /* lock down the original section so we can work with it */
- secRec = *(*(*theSections)); /* just for easier display below */
- AddResource(tempHandle, rSectionType, secRec.sectionID, "");
- /* now do the same with the alias record please */
- tempHandle = (Handle)secRec.alias;
- HandToHand(&tempHandle);
-
- AddResource(tempHandle, rAliasType, secRec.sectionID, "");
- HUnlock((Handle)*theSections);
- /* save off the display rect for this pub */
-
- tempHandle = NewHandle(sizeof(Rect));
- PtrToHand((Ptr)tempRectPtr, &tempHandle, sizeof(Rect));
- HandToHand(&tempHandle);
- AddResource(tempHandle, 'RECT', secRec.sectionID, "");
- if (secRec.mode == pumOnSave) {
- MyUpdateEdition(*theSections);
- /* and indicate that this was saved with a document */
- (*(*theSections))->refCon |= kSavedOnce; /* OR in our saved flag with type */
- }
- } /* writeEm if for pubs */
-
- if (dereg) {
- UnRegisterSection(*theSections);
- /* first see if this publisher has ever been saved with a document. If it hasn't */
- /* then we'll delete it. */
- if (((*(*theSections))->refCon & 0xf0) == kNeverSaved) {
- OSErr myErr;
- FSSpec deleteSpec;
- Boolean myWasChanged;
- ResolveAlias(nil, ((*(*theSections))->alias), &deleteSpec, &myWasChanged);
- if (myErr = DeleteEditionContainerFile(&deleteSpec)) {
- ShowMe("\pDelete Editon", myErr);
- }
- }
-
- /* and dispose of the alias handle */
- DisposHandle((Handle)*(*(*theSections))->alias);
- /* and the section handle */
- DisposHandle((Handle)*theSections);
-
- }
- theSections += 1; /* go to next section handle please */
- tempRectPtr += 1; /* and next rectangle */
- }
- HUnlock((*theWind)->pubRects);
- HUnlock((*theWind)->pubs);
- }
- /* now save off any text sections in this document */
- if ((*theWind)->textSections) {
- textSectionHandle tempTS = (*theWind)->textSections;
- do {
- tempHandle = (Handle)(*tempTS)->theSection;
- /* make sure the text is the latest */
- RePackText(tempTS, (*theWind)->boxHandle);
- AssociateSection((SectionHandle)tempHandle, theSpec);
-
- if (writeEm) {
- HandToHand(&tempHandle);
- myErr = MemError();
- if (myErr)
- ShowMe("\p memerr", myErr);
- HLock(tempHandle); /* lock down the original section so we can work with it */
- secRec = *(*(SectionHandle)tempHandle); /* just for easier display below */
- AddResource(tempHandle, rSectionType, secRec.sectionID, "");
- /* save the alias */
- tempHandle = (Handle)secRec.alias;
- HandToHand(&tempHandle);
- AddResource(tempHandle, rAliasType, secRec.sectionID, "");
- /* now save a copy of my whole text record */
-
- tempHandle = (Handle)tempTS;
- HandToHand(&tempHandle);
- /* use the same ID number as the section, make things easy */
- /* zap any forward link in this, so StoreSection doesn't get */
- /* confused when the section is read back in */
- (*(textSectionHandle)tempHandle)->nextSection = nil;
- (*(textSectionHandle)tempHandle)->theText = nil;
- (*(textSectionHandle)tempHandle)->theSection = nil;
- AddResource(tempHandle, rMyTextRecordType, secRec.sectionID, "");
-
- /* and finally, the associated text */
- tempHandle = (*tempTS)->theText;
- HandToHand(&tempHandle);
- AddResource(tempHandle, rMyTextBlock, secRec.sectionID, "");
- if (secRec.kind == stPublisher && secRec.mode == pumOnSave) {
- MyUpdateEdition((*tempTS)->theSection);
- /* and indicate that this was saved with a document */
- (*(*tempTS)->theSection)->refCon |= kSavedOnce; /* OR in our saved flag with type */
- }
- } /* text writeem if */
-
- if (dereg) {
- UnRegisterSection((SectionHandle)tempHandle);
- /* first see if this publisher has ever been saved with a document. If it hasn't */
- /* then we'll delete it. */
- if (((*(*theSections))->refCon & 0xf0) == kNeverSaved && (*(*theSections))->kind == stPublisher) {
- OSErr myErr;
- FSSpec deleteSpec;
- Boolean myWasChanged;
- ResolveAlias(nil, (*(SectionHandle)tempHandle)->alias, &deleteSpec, &myWasChanged);
- if (myErr = DeleteEditionContainerFile(&deleteSpec)) {
- ShowMe("\pSection Save Delete Editon", myErr);
- }
- }
-
- /* and dispose of the alias handle */
- DisposHandle((Handle)(*(SectionHandle)tempHandle)->alias);
- /* and the section handle */
- DisposHandle((Handle)tempHandle);
-
- }
- tempTS = (*tempTS)->nextSection;
- } while (tempTS);
-
- }
- }
-
- /* MyCancelSection cancels this section. It removes
- * the section info from our window structure, and also de-registers the
- * section with (from) the Edition Manager. If it's a publisher, it also
- * deletes the edition file
- */
- void MyCancelSection(SectionHandle inSection, WindowPtr theWindow)
- {
- OSErr myErr;
- windowCHandle shortName;
- SectionHandle *tempPtr;
- Rect *tempRectPtr;
- register qq;
- FSSpec deleteSpec;
- Boolean myWasChanged;
- shortName = (windowCHandle)GetWRefCon(theWindow);
- HLock((Handle)shortName);
-
- /* first thing to do is deregister the thing */
- UnRegisterSection(inSection);
- if ((*inSection)->kind == stPublisher) { /* only delete publishers */
- ResolveAlias(nil, ((*inSection)->alias), &deleteSpec, &myWasChanged);
- if (myErr = DeleteEditionContainerFile(&deleteSpec)) {
- ShowMe("\pCancel Delete Editon", myErr);
- }
- }
- /* get rid of the alias handle for it */
- DisposHandle((Handle)(*inSection)->alias);
- if ((*inSection)->kind == stPublisher) {
- HLock((*shortName)->pubs); /* lock down my list of section handles */
- tempPtr = (SectionHandle *)*(*shortName)->pubs;
- for (qq = 0; qq < (*shortName)->numPubs; qq++) {
- HLock((Handle)*tempPtr);
- if ((*inSection)->sectionID == (*(*tempPtr))->sectionID) {
- DisposHandle((Handle)inSection);
- DisposeHandle((Handle)(*(*tempPtr))->alias);
- DisposHandle((Handle)*tempPtr);
- HLock((*shortName)->pubRects);
- tempRectPtr = (Rect *)*((*shortName)->pubRects);
- tempRectPtr += qq;
- if (qq != (*shortName)->numPubs) {
- register ii; /* need to move information down */
- for (ii = qq; ii < ((*shortName)->numPubs) - 1; ii++) {
- *tempPtr = *(tempPtr + 1);
- *tempRectPtr = *(tempRectPtr + 1);
- tempPtr += 1;
- tempRectPtr += 1;
- }
- }
- (*shortName)->numPubs--;
- HUnlock((*shortName)->pubs);
- MySetHandleSize((*shortName)->pubs, GetHandleSize((*shortName)->pubs) - sizeof(Handle));
- HUnlock((*shortName)->pubRects);
- MySetHandleSize((*shortName)->pubRects, (GetHandleSize((*shortName)->pubRects) - sizeof(Rect)));
-
- }
- }
- } else { /* it's a subscriber */
-
- HLock((*shortName)->subs); /* lock down my list of section handles */
- tempPtr = (SectionHandle *)*(*shortName)->subs;
- for (qq = 0; qq < (*shortName)->numSubs; qq++) {
-
- HLock((Handle)*tempPtr);
- if ((*inSection)->sectionID == (*(*tempPtr))->sectionID) {
- SectionHandle removeSection;
- Handle *tempRectHand;
- Handle *tempPicHand;
- Handle *tempPicHand2;
- removeSection = (*tempPtr);
- HLock((Handle)removeSection);
- /* When the user cancels a subscription, you do NOT want to delete the */
- /* current subscription data (the picture) at this time. Since the data should be */
- /* selectable in the document they are working on (text in a text doc, pic in a */
- /* pic doc, etc) they keep the last subscription data, and delete it */
- /* seperatly if they'd like */
- HLock((*shortName)->subRects);
- HLock((*shortName)->subDataHandle);
- tempRectHand = (Handle *)*((*shortName)->subRects);
- tempPicHand = (Handle *)*((*shortName)->subDataHandle);
- tempRectHand += qq;
- tempPicHand += qq;
-
- /* move the picture over, increase the handle by 1 */
- (*shortName)->numPicts++;
- HUnlock((*shortName)->pictHandle);
- MySetHandleSize((*shortName)->pictHandle, (GetHandleSize((*shortName)->pictHandle) + sizeof(Handle)));
- HLock((*shortName)->pictHandle);
- tempPicHand2 = (Handle *)*(*shortName)->pictHandle;
- tempPicHand2 += ((*shortName)->numPicts) - 1;
- *tempPicHand2 = *tempPicHand;
- /* move the rect over also */
- HUnlock((*shortName)->pictRects);
- MySetHandleSize((*shortName)->pictRects, (GetHandleSize((*shortName)->pictRects) + sizeof(Handle)));
- HLock((*shortName)->pictRects);
- tempPicHand2 = (Handle *)*(*shortName)->pictRects;
- tempPicHand2 += ((*shortName)->numPicts) - 1;
- *tempPicHand2 = *tempRectHand;
- HUnlock((*shortName)->pictRects);
- HUnlock((*shortName)->pictHandle);
- if ((qq + 1) != (*shortName)->numSubs) {
- register ii; /* need to move information down */
- for (ii = qq; ii < ((*shortName)->numSubs) - 1; ii++) {
- *tempPtr = *(tempPtr + 1);
- *tempRectHand = *(tempRectHand + 1);
- *tempPicHand = *(tempPicHand + 1);
- tempPtr += 1;
- tempRectHand += 1;
- tempPicHand += 1;
- }
- }
- (*shortName)->numSubs--;
- HUnlock((*shortName)->subs);
- MySetHandleSize((*shortName)->subs, GetHandleSize((*shortName)->subs) - sizeof(SectionHandle));
- HUnlock((*shortName)->subRects);
- MySetHandleSize((*shortName)->subRects, (GetHandleSize((*shortName)->subRects) - sizeof(Handle)));
-
- }
- }
- }
- HUnlock((Handle)shortName);
- /* and clear the highlight */
- if (gShowPub || gShowSub) {
- extern Rect gShowPubRect;
- extern Rect gShowSubRect;
- extern SectionHandle gShowingSecHandle;
- gShowPub = gShowSub = false;
- gShowingSecHandle = nil;
- InvalRect(&gShowPubRect);
- InvalRect(&gShowSubRect);
- }
- }
-
- /* end MyCancelSection */
-
- void StoreSubscriber(windowCHandle shortName, SectionHandle secHandle, Handle inRect, Handle pictIn)
- {
- OSErr myErr;
- SectionHandle *tempPtr;
- Handle *tempPicHand;
- Size dataSize;
- EditionRefNum sRefNum;
- /* first we need to determine if this is a PICT or TEXT subscription, since I'm handling */
- /* them differently for drill. */
- myErr = OpenEdition(secHandle, &sRefNum);
- if (myErr = EditionHasFormat(sRefNum, 'PICT', &dataSize))
- (*secHandle)->refCon |= kTextType;
- else
- (*secHandle)->refCon |= kPictType;
- /* Now that little mechanism could screw up, if the formats of the section have been */
- /* changed since the subscription was originally created. But it'll work here */
- CloseEdition(sRefNum, true);
-
- /* increase our section handle holding handle by the size of a handle */
- if (((*secHandle)->refCon & 0xf) == kPictType) {
- HUnlock((*shortName)->subs);
- MySetHandleSize((*shortName)->subs, GetHandleSize((*shortName)->subs) + sizeof(SectionHandle));
- HLock((*shortName)->subs);
- /* dereference the handle to our section handles in our window structure */
- /* and cast it to a pointer to section handles, since that's what it contains */
- tempPtr = (SectionHandle *)((*(*shortName)->subs) + (sizeof(SectionHandle) * ((*shortName)->numSubs)));
- /* and store our subscriber section */
- *tempPtr = (SectionHandle)secHandle;
- HUnlock((*shortName)->subs); /* let it float again */
- /* Here I'm setting up a handle for the picture data contained in the edition we just */
- /* subscribed to, in an array of handles held in the handle subDataHandle */
- HUnlock((*shortName)->subDataHandle);
- MySetHandleSize((*shortName)->subDataHandle, GetHandleSize((*shortName)->subDataHandle) + sizeof(Handle)); /* allocate */
- HLock((*shortName)->subDataHandle);
- /* deref it */
- tempPicHand = (Handle *)*((*shortName)->subDataHandle);
- tempPicHand += ((*shortName)->numSubs);
-
- if (pictIn == nil)
- *tempPicHand = NewHandle(0); /* set up a nil handleo */
- else
- *tempPicHand = pictIn;
- /* ••• NOTE: You do _NOT_ read the data contained in this section yet! */
- /* All you have done is subscribed to it, the Edition Manager has not told you */
- /* that you can read it! Wait for the section read event (see below) to get the */
- /* data. SO I store an empty handle here as a placeholder */
- MoveHHi(*tempPicHand);
- HUnlock((*shortName)->subRects);
- MySetHandleSize((*shortName)->subRects, (GetHandleSize((*shortName)->subRects) + sizeof(Handle))); /* allocate a new re*/
- myErr = MemError();
- if (myErr)
- ShowMe("\pMemory error ", myErr);
- HLock((*shortName)->subRects);
- /* generate an empty display rectangle handle also */
- tempPicHand = (Handle *)*((*shortName)->subRects);
- tempPicHand += ((*shortName)->numSubs);
- if (inRect == nil)
- *tempPicHand = NewHandle(0); /* set up a nil handleo */
- else
- *tempPicHand = inRect;
- MoveHHi(*tempPicHand);
- (*shortName)->numSubs++; /* increment our count of subscribers */
- HUnlock((*shortName)->subRects);
- HUnlock((*shortName)->subDataHandle);
- } else {
- if (((*secHandle)->refCon & 0xf) == kTextType) { /* double checking here */
- textSectionHandle newSection;
- /* get a new text section record */
- if (inRect == nil) {
- /* this means that it is being created fresh, so we have to get a */
- /* text section record from my routine */
- newSection = GetTextSection(shortName, stSubscriber);
- /* fill it with stuff relating to the section we just created */
- (*newSection)->publishing = false;
- (*newSection)->theID = (*secHandle)->sectionID;
- (*newSection)->theSection = secHandle;
- } else {
- newSection = (textSectionHandle)inRect;
- }
- /* store it in our window structure */
- if ((*shortName)->textSections) {
- textSectionHandle tempSection = (*shortName)->textSections;
- if ((*shortName)->textSections) {
- while ((*tempSection)->nextSection)
- tempSection = (*tempSection)->nextSection;
- }
- (*tempSection)->nextSection = newSection;
-
- } else {
- /* first one */
- (*shortName)->textSections = newSection;
- }
- }
- }
- }
-
- pascal short SubExpOptHook(short itemOffset, short itemHit, DialogPtr theDialog, Ptr yourDataPtr)
- {
- short myHit;
- short itemType;
- ControlHandle theButton;
- Rect theRect;
- /* first make sure that a sub-dialog is not frontmost */
- /* so we don't filter keys or hits to a sub-dialog */
- if (GetWRefCon((WindowPtr)theDialog) == 'stdf' || GetWRefCon((WindowPtr)theDialog) == 'optn') {
- /* first see if it's the 'first call' item (see the Standard File chapter). If it is, then */
- /* we preset our check box */
- if (itemHit == -1) {
- /* this gets the handle to our check box, since we know it's one past the last standard item */
- GetDItem(theDialog, itemOffset + 1, &itemType, (Handle *)&theButton, &theRect);
- SetCtlValue(theButton, gResizeSub); /* and set our current value */
- } else {
- /* only have one item in this expansion, but we'll check the range anyway to be safe */
- myHit = itemHit - itemOffset; /* since our item numbers are relative to the total number */
- /* of items in the dialog, and the system may change. Always do your item numbering based */
- /* on the offset, this will prevent incompatability when the system dialog grows or shrinks */
- if (myHit == 1) { /* I only added one item, so this be the one */
- /* Pass itemHit here, not myHit, since the dialog manager has no idea that this is an */
- /* additive dialog. It is counting from the actual start of the DITL, not the start of */
- /* your custom items */
- GetDItem(theDialog, itemHit, &itemType, (Handle *)&theButton, &theRect);
- if (GetCtlValue(theButton))
- gResizeSub = false;
- else
- gResizeSub = true;
- SetCtlValue(theButton, gResizeSub);
- }
- }
- }
- return(itemHit); /* the return value must be absolute */
- }
-
- pascal Boolean SubExpOptFilter(DialogPtr theDialog, EventRecord *theEvent, short itemOffset, short *itemHit, Ptr yourDataPtr)
- {
- short myHit;
- short itemType;
- ControlHandle theButton;
- Rect theRect;
- /* first make sure that a sub-dialog is not frontmost */
- /* so we don't filter keys or hits to a sub-dialog */
- if (GetWRefCon((WindowPtr)theDialog) == 'stdf' || GetWRefCon((WindowPtr)theDialog) == 'optn') {
- /* standard filter proc kinda stuff here */
- if ((theEvent->what) == keyDown) {
- char tempChar;
- tempChar = theEvent->message & charCodeMask;
-
- if (((tempChar == 'A') || (tempChar == 'a')) && (theEvent->modifiers & cmdKey)) {
- /* they pressed an A with the command key down, we get to handle it. */
- GetDItem(theDialog, itemOffset + 1, &itemType, (Handle *)&theButton, &theRect);
- if (GetCtlValue(theButton))
- gResizeSub = false;
- else
- gResizeSub = true;
- SetCtlValue(theButton, gResizeSub);
- return(true); /* tell folks we handled it */
- }
- }
- }
- return(false); /* was not a keystroke we wanted */
-
- }
-
- /* DeleteSubscriber is called by a menu command 'Clear' */
-
- void DeleteSubscriber(void)
- {
- if (StopAlert(kCanxSub, nil) == 2) {
- MyCancelSection(gShowingSecHandle, FindSection(gShowingSecHandle));
-
- }
- }
-
- /* end DeleteSubscriber */
-
- /* PasteSubscription pastes the section (a subscriber) from the clipboard into the */
- /* frontmost window (as you would expect) */
- void PasteSubscription(void)
- {
-
- windowCHandle tempWC;
- SectionHandle tempHandle;
- AliasHandle tempHandle2;
- Handle tempRectHand;
- FSSpec newFileSpec;
- Boolean myWasChanged;
- Rect tempPRect = {0,0,40,40};
- long myOffset;
- long fred;
- PicHandle tempPicHandle;
- tempRectHand = NewHandle(sizeof(Rect));
- /* first see if there is a section handle on the clipboard */
- /* kill the current section on the clipboard, if there is one */
- /* •••• NEW, we're looking for section handles and aliases on the clipboard. */
-
- /* set up a dummy picture for this incoming section.... */
- if(!gScrapData)gScrapData=NewHandle(0);
- fred=GetScrap(gScrapData, rSectionType, &myOffset);
- if( fred > 0 ){
- myOffset=0;
- /* read in the rect also */
- fred = GetScrap(tempRectHand,'RECT',&myOffset);
- if(fred > 0 ){
- /* and read in the pict */
- myOffset=0;
- GetScrap((Handle)gClipPict,'PICT',&myOffset);
- }
- }
- HLock(tempRectHand);
- tempWC = (windowCHandle)GetWRefCon(gCurrentWindow);
- HLock((Handle)tempWC);
- if(gClipPict){*(Rect *)(*tempRectHand) = (*gClipPict)->picFrame;
- InvalRect(&(*gClipPict)->picFrame); /* make sure it gets drawn */
- } else {
- *(Rect *)(*tempRectHand)=tempPRect;
- }
- /* update the ID of the section to include the master ID of the window yer pasting into */
- (*gClipSection)->sectionID += (*tempWC)->windowID;
- StoreSubscriber(tempWC, gClipSection, tempRectHand, (Handle)gClipPict);
- HUnlock((Handle)tempWC);
- /* Now, after you paste the subscription, you have to change the subscription on the clipboard. */
- /* You need to duplicate it, and assign a new ID number, since if the thing is pasted again */
- /* you could have two subscriptions with the same ID, which would not be nice. So we do this... */
- tempHandle = gClipSection;
- tempHandle2 = (*gClipSection)->alias;
- HandToHand((Handle *)&tempHandle);
- HandToHand((Handle *)&tempHandle2);
- (*tempHandle)->sectionID = gSectionID;
- (*tempHandle)->alias = tempHandle2;
- gSectionID++;
- /* now register the section so the edition manager knows to send you updates */
- ResolveAlias(nil, tempHandle2, &newFileSpec, &myWasChanged);
- if ((RegisterSection(&newFileSpec, tempHandle, &myWasChanged))==noErr)
- gClipSection = tempHandle;
- // gClipPict = (PicHandle)NewHandle(0); /* allocate an empty handle for this picture data */
- gClipHasContents = kClipHasSub;
- MyReadSection(tempHandle);
-
- }
- /* CutSubscription and CopySubscription move the current selection in the active window to the */
- /* ClipBoard. The main difference here from standard scrap handling is that the scrap you now */
- /* have is dynamic. The contents of the clipboard can change if the publisher of this subscription */
- /* changes, so you must treat this section as you would any other subscriber */
- /* frontmost window (as you would expect) */
- void CutSubscription(void)
- {
- CopySubscription();
- DeleteSubscriber(); /* even though they said cut, I want to make sure that they really mean it */
- }
- /* CopySubscriber moves the current display subscriber to the clipboard, making a new */
- /* subscription in the process, since we don't want to have two copies of the same thing */
- void CopySubscription(void)
- {
- SectionHandle tempHandle;
- AliasHandle tempHandle2;
- FSSpec newFileSpec;
- Boolean myWasChanged;
- /* First check to see if there is already a section to remove */
- if (gClipHasContents == kClipHasSub) {
- KillClipSub();
- }
- tempHandle = gShowingSecHandle;
- /* copy the alias also */
- tempHandle2 = (*gShowingSecHandle)->alias;
- HandToHand((Handle *)&tempHandle);
- HandToHand((Handle *)&tempHandle2);
- /* create a unique ID for this section. I'll just use the next section ID */
- (*tempHandle)->sectionID = gSectionID;
- (*tempHandle)->alias = tempHandle2;
- gSectionID++;
- /* now register the section so the edition manager knows to send you updates */
- ResolveAlias(nil, tempHandle2, &newFileSpec, &myWasChanged);
- if ((RegisterSection(&newFileSpec, tempHandle, &myWasChanged))==noErr)
- gClipSection = tempHandle;
- gClipPict = (PicHandle)NewHandle(0); /* allocate an empty handle for this picture data */
- gClipHasContents = kClipHasSub;
- /* write the section handle out to the cipboard */
- ZeroScrap();
- PutScrap(sizeof(Handle),rSectionType,(Ptr)&tempHandle);
- PutScrap(sizeof(Rect),'RECT',(Ptr)&gShowSubRect);
-
- MyReadSection(tempHandle);
-
- InitCursor(); /* set to watch by MyReadSection, would normally be reset next pass */
- /* through the event loop, but NOT if it's being called by Cut, */
- /* so I'll reset it just to be safe */
- }
-
- OSErr ReadClipSection(Size readIn, EditionRefNum sRefNum)
- {
- extern Handle gScrapData;
- WindowPtr temp;
- MySetHandleSize((Handle)gClipPict, readIn);
- HLock((Handle)gClipPict);
- /* read the pict in */
- MyReadEditionData((Ptr)*gClipPict, 'PICT', sRefNum, &readIn);
- HUnlock((Handle)gClipPict);
- gScrapData = (Handle)gClipPict;
- if (((WindowPeek)gClipWindowPtr)->visible) {
- WindowPtr temp;
- GetPort(&temp);
- SetPort(gClipWindowPtr);
- InvalRect(&gClipWindowPtr->portRect);
- SetPort(temp);
- }
- }
- /* This kills the current section on the clipboard, since it's being replaced */
- /* and you don't want to receive events for it anymore */
- void KillClipSub(void)
- {
- UnRegisterSection(gClipSection);
- DisposHandle((Handle)(*gClipSection)->alias);
- DisposeHandle((Handle)gClipSection);
- gClipSection = nil;
- gClipHasContents = kClipEmpty;
- if (GetHandleSize((Handle)gClipPict) != nil)
- KillPicture(gClipPict);
- }
-
- /* MyGoToPublisher is used if the user was holding down the Option key during a */
- /* double click, to send them to the publisher without seeing the dialog box */
- OSErr MyGoToPublisher(SectionHandle theSection)
- {
- EditionInfoRecord theEdInfo;
-
- GetEditionInfo(theSection, &theEdInfo);
- GoToPublisherSection(&theEdInfo.container);
- }
-
-
- #undef __SUBSCRIBE__
-